package com.glela.api.upload.qiniu.http;

import java.util.Map;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;

/**
 * HTTP请求类
 * 
 * @author liujie
 */
public class HttpProtocolHandler
{

	/**
	 * 工厂方法
	 * 
	 * @return
	 */
	public static HttpProtocolHandler getInstance()
	{
		return httpProtocolHandler;
	}

	private static String DEFAULT_CHARSET = "GBK";

	/** 连接超时时间，由bean factory设置，缺省为8秒钟 */
	private final int defaultConnectionTimeout = 8000;

	/** 回应超时时间, 由bean factory设置，缺省为30秒钟 */
	private final int defaultSoTimeout = 30000;

	/** 闲置连接超时时间, 由bean factory设置，缺省为60秒钟 */
	private final int defaultIdleConnTimeout = 60000;

	private final int defaultMaxConnPerHost = 30;

	private final int defaultMaxTotalConn = 80;

	/** 默认等待HttpConnectionManager返回连接超时（只有在达到最大连接数时起作用）：1秒 */
	private static final long defaultHttpConnectionManagerTimeout = 3 * 1000;

	/**
	 * HTTP连接管理器，该连接管理器必须是线程安全的.
	 */
	private final HttpConnectionManager connectionManager;

	private static HttpProtocolHandler httpProtocolHandler = new HttpProtocolHandler();

	/**
	 * 私有的构造方法
	 */
	private HttpProtocolHandler()
	{
		// 创建一个线程安全的HTTP连接池
		connectionManager = new MultiThreadedHttpConnectionManager();
		connectionManager.getParams().setDefaultMaxConnectionsPerHost(defaultMaxConnPerHost);
		connectionManager.getParams().setMaxTotalConnections(defaultMaxTotalConn);
	}

	/**
	 * 执行Http请求
	 * 
	 * @param request
	 *            请求数据
	 * @param strParaFileName
	 *            文件类型的参数名
	 * @param strFilePath
	 *            文件路径
	 * @return
	 * @throws HttpException
	 *             , IOException
	 */
	public HttpResponse execute(HttpRequest request) throws HttpException, Exception
	{
		HttpClient httpclient = new HttpClient(connectionManager);
		String charset = request.getCharset();

		httpclient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charset);

		// 设置连接超时
		int connectionTimeout = defaultConnectionTimeout;
		if (request.getConnectionTimeout() > 0) {
			connectionTimeout = request.getConnectionTimeout();
		}
		httpclient.getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);

		// 设置回应超时
		int soTimeout = defaultSoTimeout;
		if (request.getTimeout() > 0) {
			soTimeout = request.getTimeout();
		}
		httpclient.getHttpConnectionManager().getParams().setSoTimeout(soTimeout);

		// 设置等待ConnectionManager释放connection的时间
		httpclient.getParams().setConnectionManagerTimeout(defaultHttpConnectionManagerTimeout);

		charset = charset == null ? DEFAULT_CHARSET : charset;
		HttpMethod method = null;

		// get模式且不带上传文件
		if (request.getMethod().equals(HttpRequest.METHOD_GET)) {
			method = new GetMethod(request.getUrl());
			method.getParams().setCredentialCharset(charset);
			method.setQueryString(request.getQueryString());
		}
		else {
			method = new PostMethod(request.getUrl());
			if (request.getParameters() != null) {
				NameValuePair[] pairs = new NameValuePair[request.getParameters().size()];
				((PostMethod) method).addParameters(request.getParameters().toArray(pairs));
			}
		}

		if (request.getHeads() != null) {
			for (Map.Entry<String, String> entry : request.getHeads().entrySet()) {
				method.addRequestHeader(entry.getKey(), entry.getValue());
			}
		}
		method.addRequestHeader("User-Agent", "Mozilla/4.0");
		HttpResponse response = new HttpResponse();

		try {
			response.setHttpCode(httpclient.executeMethod(method));
			if (request.getResultType().equals(HttpResultType.STRING)) {
				response.setStringResult(method.getResponseBodyAsString());
			}
			else if (request.getResultType().equals(HttpResultType.BYTES)) {
				response.setByteResult(method.getResponseBody());
			}
			response.setResponseHeaders(method.getResponseHeaders());
		}
		catch (Exception ex) {
			ex.printStackTrace();
			throw ex;
		}
		finally {
			method.releaseConnection();
		}
		return response;
	}

	/**
	 * 将NameValuePairs数组转变为字符串
	 * 
	 * @param nameValues
	 * @return
	 */
	protected String toString(NameValuePair[] nameValues)
	{
		if (nameValues == null || nameValues.length == 0) {
			return "null";
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < nameValues.length; i++) {
			NameValuePair nameValue = nameValues[i];

			if (i == 0) {
				buffer.append(nameValue.getName() + "=" + nameValue.getValue());
			}
			else {
				buffer.append("&" + nameValue.getName() + "=" + nameValue.getValue());
			}
		}

		return buffer.toString();
	}
}
